﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Objects.DataClasses;
using BaseWordStat;
using System.Linq;

namespace DbLayer
{
    public class DbProxy
    {
        public static void AddArticleDb(Article article)
        {
            using (var db = new TestDbEntities())
            {
                var author = AddAuthor(article.Author, db);

                if (author == null)
                    return;

                var articleDb = AddArticle(article.Title, article.Date, article.Text, article.Url, db);

                if (articleDb == null)
                    return;

                AddAuthorArticle(articleDb, author, db);

                var words = PrepareWords(article.Words);

                var dbWords = AddWords(words.Keys, db);

                AddArticleWords(articleDb, dbWords, words, db);

                db.SaveChanges();
            }
        }

        private static void AddArticleWords(Articles articleDb, IEnumerable<Words> dbWords, IDictionary<string, int> words, TestDbEntities db)
        {
            foreach (var dbWord in dbWords)
            {
                if (!words.ContainsKey(dbWord.WordText))
                    continue;

                var aw = new ArticleWords { Articles = articleDb, Words = dbWord, WordCount = words[dbWord.WordText] };

                db.AddToArticleWords(aw);
            }

            db.SaveChanges();
        }

        internal static IDictionary<string, int> PrepareWords(Dictionary<string, int> words)
        {
            return words.ToDictionary(word => word.Key.ToLower(), word => word.Value);
        }

        private static List<Words> AddWords(ICollection<string> words, TestDbEntities db)
        {
            var res = new List<Words>();
            var wordList = new List<string>(words);

            var list = db.Words.Where(dbWord => words.Contains(dbWord.WordText));

            foreach (var wIter in list)
                wordList.Remove(wIter.WordText);

            foreach (var dbWord in wordList.Select(word => new Words { WordText = word }))
            {
                res.Add(dbWord);

                db.AddToWords(dbWord);
            }

            db.SaveChanges();

            return res;
        }

        private static void AddAuthorArticle(Articles articleD, Authors author, TestDbEntities db)
        {
            var authorArticle = new AuthorArticles();

            authorArticle.ArticlesReference.EntityKey = new EntityKey("TestDbEntities.Articles", "ArticleId", articleD.ArticleId);
            authorArticle.AuthorsReference.EntityKey = new EntityKey("TestDbEntities.Authors", "AuthorId", author.AuthorId);
            //authorArticle.Articles = articleD;
            //authorArticle.Authors = author;
            //db.AuthorArticles.AddObject(authorArticle); 
            db.AddToAuthorArticles(authorArticle);
            db.SaveChanges();
        }

        private static Authors AddAuthor(string authorName, TestDbEntities db)
        {
            var author = db.Authors.Where(a => a.NameSurname == authorName).FirstOrDefault();

            if (author != null)
                return author;

            var newAuthor = new Authors { NameSurname = authorName };

            db.AddToAuthors(newAuthor);

            db.SaveChanges();

            return newAuthor;
        }

        private static Articles AddArticle(string title, DateTime date, string articleText, string articleUrl, TestDbEntities db)
        {
            var article = new Articles
                              {
                                  ArticleTitle = title,
                                  ArticleText = articleText,
                                  ArticleUrl = articleUrl,
                                  ArticleDate = date
                              };

            db.AddToArticles(article);

            db.SaveChanges();

            return article;
        }

        public static Dictionary<string, int> GetAllWordsData(int page, int itemOnPages, string source)
        {
            using (var db = new TestDbEntities())
            {
                var toSkip = page * itemOnPages;

                var res = (from wd in db.Words
                           join aw in db.ArticleWords on wd.WordId equals aw.WordId into awres
                           select new { wd.WordText, WordCount = awres.Sum(a => a.WordCount) }
                           ).OrderBy(wd => wd.WordText).OrderBy(wd => wd.WordCount).Skip(toSkip).Take(itemOnPages);

                return res.ToDictionary(iter => iter.WordText, iter => iter.WordCount.Value);
            }
        }

        public static IDictionary<Article, int> GetArticles(string wordText, string currentSource)
        {
            using (var db = new TestDbEntities())
            {
                var wordId = (from w in db.Words where wordText == w.WordText select w.WordId).FirstOrDefault();

                var articlids = (from wa in db.ArticleWords
                                 where wa.WordId == wordId
                                 select new { wa.ArticleId, wa.WordCount });

                var dic = articlids.ToDictionary(articlid => articlid.ArticleId.Value, articlid => articlid.WordCount.Value);

                var list = dic.Select(d => d.Key);

                var articles = from a in db.Articles where list.Contains(a.ArticleId) select new { a.ArticleTitle, a.ArticleUrl, a.ArticleId, a.ArticleText };

                var res = new Dictionary<Article, int>();

                foreach (var article in articles)
                {
                    var a = new Article { Title = article.ArticleTitle, Url = article.ArticleUrl, Text = article.ArticleText };

                    res.Add(a, dic[article.ArticleId]);
                }

                return res;
            }
        }
    }
}
